package com.app.service.Impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.app.aspect.RedisLockAnnotation;
import com.app.common.TotalConfig;
import com.app.exception.BaseException;
import com.app.mapper.*;
import com.app.pojo.*;
import com.app.service.IPaymentRecordsLogService;
import com.app.util.IpUtil;
import com.app.util.PriceUtils;
import com.app.util.Result;
import com.app.vo.AdminHomePageVo;
import com.app.vo.PaymentRecordsLogVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 缴费记录表 服务实现类
 * </p>
 *
 * @author yoominic
 * @since 2024-07-29
 */
@Slf4j
@Service
public class PaymentRecordsLogServiceImpl extends ServiceImpl<PaymentRecordsLogMapper, PaymentRecordsLog> implements IPaymentRecordsLogService {

    @Value("${wx.pay.mchId}")
    private String mchId;
    @Value("${wx.pay.payNotify}")
    private String payNotify;
    @Autowired
    private WxPayService wxService;
    @Autowired
    private PaymentRecordsLogMapper paymentRecordsLogMapper;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private GasDetailsMapper gasDetailsMapper;
    @Autowired
    private RequestLogsServiceImpl requestLogsService;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private RefundRecordsLogMapper refundRecordsLogMapper;

    static ThreadPoolExecutor cacheThreadPool = new ThreadPoolExecutor(1, 10,
            1, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>());

    @Override
    public PaymentRecordsLogVo getPaymentRecordslISTByUserId(String userId, Integer page, Integer limit) {
        QueryWrapper<PaymentRecordsLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        queryWrapper.eq("state",2);
        queryWrapper.orderByDesc("create_time");
        Page<PaymentRecordsLog> page1 = new Page<>(page, limit);
        Page<PaymentRecordsLog> pageList = paymentRecordsLogMapper.selectPage(page1, queryWrapper);
        List<PaymentRecordsLog> communityList = pageList.getRecords();

        PaymentRecordsLogVo paymentRecordsLogVo = new PaymentRecordsLogVo();
        paymentRecordsLogVo.setCount((int) pageList.getTotal());
        paymentRecordsLogVo.setList(communityList);
        return paymentRecordsLogVo;
    }



    @Override
    @RedisLockAnnotation(prefix = "createRechargeBalanceOrder_", key = "#userId")
    public Object createPayGasOrder(PaymentRecordsLog paymentRecordsLog, Integer userid) {
        String account = paymentRecordsLog.getAccount();
        GasDetails gasDetails = gasDetailsMapper.selectOne(new QueryWrapper<GasDetails>().eq("account", account).eq("status", 1));
        String companyName = paymentRecordsLog.getCompanyName();
        Company company = companyMapper.selectOne(new QueryWrapper<Company>().eq("company_name", companyName));

        //未开户，则需要先下发开户指令
        Integer accountOpeningStatus = gasDetails.getAccountOpeningStatus();
        if (null == accountOpeningStatus || 0 == accountOpeningStatus ){
            com.alibaba.fastjson.JSONObject push_open_account = requestLogsService.pushGasRequestLogs("000E",account, "1");
            System.err.println("开户指令下发结果："+push_open_account);
            if ("0".equals(push_open_account.get("code")+"")){
                paymentRecordsLog.setCompanyId(company.getId());
                paymentRecordsLog.setUserName(gasDetails.getUserName());
                paymentRecordsLog.setUserAddress(gasDetails.getUserAddress());
                paymentRecordsLog.setOrderNo(IdUtil.simpleUUID());
                paymentRecordsLog.setUserId(userid);
                paymentRecordsLog.setType("1");
                paymentRecordsLog.setState("1");//待支付
                paymentRecordsLog.setCreateTime(LocalDateTime.now());

                //更新开户状态
                gasDetails.setAccountOpeningStatus(1);
                gasDetailsMapper.updateById(gasDetails);
                //保存支付记录到数据库
                paymentRecordsLogMapper.insert(paymentRecordsLog);
                //微信支付
                User user = userMapper.selectById(userid);
                return wechatPayGasOrder(paymentRecordsLog,user,"燃气缴费充值","燃气缴费充值");
            }else {
//                return Result.error("燃气表开户异常！请稍后再试！");
                throw new BaseException(400, "燃气表开户异常！请稍后再试！");
            }
        }else {

            paymentRecordsLog.setCompanyId(company.getId());
            paymentRecordsLog.setUserName(gasDetails.getUserName());
            paymentRecordsLog.setUserAddress(gasDetails.getUserAddress());
            paymentRecordsLog.setOrderNo(IdUtil.simpleUUID());
            paymentRecordsLog.setUserId(userid);
            paymentRecordsLog.setType("1");
            paymentRecordsLog.setState("1");//待支付
            paymentRecordsLog.setCreateTime(LocalDateTime.now());
            //保存支付记录到数据库
            paymentRecordsLogMapper.insert(paymentRecordsLog);
            //微信支付
            User user = userMapper.selectById(userid);
            return wechatPayGasOrder(paymentRecordsLog,user,"燃气缴费充值","燃气缴费充值");
        }

    }


    public Object wechatPayGasOrder(PaymentRecordsLog paymentRecordsLog, User userInfo,String body,String text){
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String ip = IpUtil.getIpAddress(request);
        WxPayUnifiedOrderRequest requestBody = new WxPayUnifiedOrderRequest();
        requestBody.setAttach(text);

        requestBody.setBody(body);
        requestBody.setOutTradeNo(paymentRecordsLog.getOrderNo());
        requestBody.setTotalFee(PriceUtils.changeY2F(paymentRecordsLog.getPayMoney().doubleValue()));
        requestBody.setSpbillCreateIp(ip);
        requestBody.setNotifyUrl(payNotify);
        requestBody.setOpenid(userInfo.getOpenId());
        requestBody.setTradeType(WxPayConstants.TradeType.JSAPI);
        try {
            Object response = wxService.createOrder(requestBody);
            log.info(JSONUtil.toJsonStr(response));
            JSONObject object = JSONUtil.parseObj(response);
            object.set("package", object.getStr("packageValue"));
            object.set("prePayParams", mchId);
            object.set("orderSn", paymentRecordsLog.getOrderNo());
            return object;
        } catch (WxPayException e) {
            log.info("请求失败,{}", e.getReturnMsg());
            throw new BaseException(400, e.getReturnMsg());
        }
    }


    //微信退款方法
    public Object refund(RefundRecordsLog order, String text) {
        try {
            log.info("transactionId: {} ", order.getOrderNo());
            WxPayRefundRequest request = new WxPayRefundRequest();
            request.setTotalFee(PriceUtils.changeY2F(order.getPayMoney().doubleValue()));
            request.setOutTradeNo(order.getOrderNo());
            request.setOutRefundNo(order.getOrderNo());
            request.setRefundDesc(text);
            request.setRefundFee(PriceUtils.changeY2F(order.getPayMoney().doubleValue()));
//            request.setNotifyUrl(refundNotify);
            Object response = this.wxService.refund(request);
            log.info("退款信息: {}", response);
            return "SUCCESS";
        } catch (WxPayException e) {
            throw new BaseException(400, e.getCustomErrorMsg());
        }
    }


    //退款生成 退款订单  发送退款请求
    @Override
    @RedisLockAnnotation(prefix = "rechargeOrderCallback_", key = "#orderId")
    public void parseOrderNotifyResult(String orderId, Double orderAmount) {
        QueryWrapper<PaymentRecordsLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderId);
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("limit 1");
        PaymentRecordsLog order = paymentRecordsLogMapper.selectOne(queryWrapper);
        String account = "";
        BigDecimal new_amount = new BigDecimal("0");
        if (order != null && order.getState().equals("1")) {
            //验证价格
            if (order.getPayMoney().compareTo(BigDecimal.valueOf(orderAmount)) != 0) {
                throw new BaseException(500, "价格校验失败");
            }

            account = order.getAccount();
            //更新订单状态
            order.setState("2");
            paymentRecordsLogMapper.updateById(order);
            //更新用户余额
            QueryWrapper<GasDetails> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("account", account);
            GasDetails gasDetails = gasDetailsMapper.selectOne(queryWrapper1);
            if (gasDetails != null) {
                Integer valve_status = gasDetails.getValveStatus();
                new_amount = gasDetails.getBalance().add(order.getPayMoney());

                gasDetails.setBalance(new_amount);

                //更新燃气表余额
                gasDetails.setGasMeterBalance(new_amount);
//                //更新购入总量  缴费金额 / 单价 保留两位小数
                gasDetails.setTotalPurchaseAmount(gasDetails.getTotalPurchaseAmount().add(order.getPayMoney().divide(gasDetails.getUnitPrice(), 2, BigDecimal.ROUND_HALF_UP)));

                //判断阀门如果为关  且 最新余额大于0  则打开阀门
                if ((null == valve_status) || (null != valve_status && 0 == valve_status && new_amount.compareTo(BigDecimal.ZERO) > 0) ){
                    //发送阀门打开指令
                    com.alibaba.fastjson.JSONObject push_open_valve = requestLogsService.pushGasRequestLogs("0001",account, "0");
                    if ("200".equals(push_open_valve.get("code"))){
                        gasDetails.setValveStatus(1);
                    }
                }
                gasDetailsMapper.updateById(gasDetails);

            }

            //上报购买气量   气量*1000
//            requestLogsService.pushGasRequestLogs("0018",account, gasDetails.getTotalPurchaseAmount().multiply(BigDecimal.valueOf(1000)).toString());

            //上报账户余额
            //余额*1000
//            requestLogsService.pushGasRequestLogs("000F",account, new_amount.multiply(BigDecimal.valueOf(100)).toString());
        }
    }


    //解析微信支付回调结果  数据库处理
    @Override
    @RedisLockAnnotation(prefix = "refundRecharge_", key = "#outTradeNo")
    @Transactional(rollbackFor = Exception.class)
    public void receiveWechatRefundInfo(String outTradeNo, String result) {
        QueryWrapper<RefundRecordsLog> rechargeRefundQueryWrapper = new QueryWrapper<>();
        rechargeRefundQueryWrapper.eq("order_no", outTradeNo);
        RefundRecordsLog rechargeRefund = refundRecordsLogMapper.selectById(rechargeRefundQueryWrapper);
        //充值退款的订单
        if (rechargeRefund != null) {
            if ("1".equals(rechargeRefund.getState())) {
                if (result.equals("SUCCESS")) {
                    rechargeRefund.setState("2");
                    refundRecordsLogMapper.updateById(rechargeRefund);
                    //更新用户余额
                    //因为充值成功时，累加了余额，所以这里需要减去退款金额
                    QueryWrapper<GasDetails> queryWrapper1 = new QueryWrapper<>();
                    queryWrapper1.eq("account", rechargeRefund.getAccount());
                    GasDetails gasDetails = gasDetailsMapper.selectOne(queryWrapper1);
                    if (gasDetails != null) {
                        BigDecimal new_amount = gasDetails.getBalance().subtract(rechargeRefund.getPayMoney());
                        gasDetails.setBalance(new_amount);
                        gasDetailsMapper.updateById(gasDetails);
                    }
                }
            }
        }
    }



    /**
     * admin查询缴费记录
     *
     * @param page
     * @param limit
     * @param keyword
     * @param state
     * @return
     */
    @Override
    public Result<Object> paymentRecord(Integer page, Integer limit, String keyword, Integer state) {
        Page<PaymentRecordsLog> page1 = new Page<>(page, limit);
        Page<PaymentRecordsLog> paymentRecordsLogPage = paymentRecordsLogMapper.selectPage(page1, new QueryWrapper<PaymentRecordsLog>()
                .like(StrUtil.isNotBlank(keyword), "user_name", keyword)
                .eq(StrUtil.isNotBlank(keyword), "account", keyword)
                .eq(StrUtil.isNotBlank(keyword), "order_no", keyword)
                .eq((state!=null&& state>0 && state<4), "state", state));
        List<PaymentRecordsLog> paymentRecordsLogs = paymentRecordsLogPage.getRecords();
        for (PaymentRecordsLog paymentRecordsLog : paymentRecordsLogs) {
            String type = paymentRecordsLog.getType();
            String state_str = paymentRecordsLog.getState();
            switch (state_str){//状态 1待支付 2已支付 3支付失败
                case "1":
                    paymentRecordsLog.setStateStr(TotalConfig.PENDING_PAYMENT);
                    break;
                case "2":
                    paymentRecordsLog.setStateStr(TotalConfig.PAID_ALREADY);
                    break;
                case "3":
                    paymentRecordsLog.setStateStr(TotalConfig.PAYMENT_FAILED);
            }
            switch (type){//1燃气费
                case "1":
                    paymentRecordsLog.setTypeStr(TotalConfig.GAS_COST);
            }
        }
        PaymentRecordsLogVo paymentRecordsLogVo = new PaymentRecordsLogVo();
        paymentRecordsLogVo.setCount((int) paymentRecordsLogPage.getTotal());
        paymentRecordsLogVo.setList(paymentRecordsLogPage.getRecords());
        return Result.success(paymentRecordsLogVo);
    }


    /**
     * Admin首页查询缴费总金额
     * @return
     */
    @Override
    public BigDecimal sumMoney() {
        BigDecimal sumMoney = paymentRecordsLogMapper.sumMoney();
        return sumMoney;
    }

    /**
     * Admin首页查询近三十天缴费金额
     * @return
     */
    @Override
    public Result<AdminHomePageVo> paymentAmount() {
        List<AdminHomePageVo> adminHomePageVos =  paymentRecordsLogMapper.paymentAmount();
        AdminHomePageVo adminHomePageVo = new AdminHomePageVo();
        ArrayList<String> day = new ArrayList<>();
        ArrayList<BigDecimal> paymentAmount = new ArrayList<>();
        for (AdminHomePageVo homePageVo : adminHomePageVos) {
            day.add(homePageVo.getData1());
            paymentAmount.add(homePageVo.getData3());
        }
        adminHomePageVo.setDay(day);
        adminHomePageVo.setPaymentAmountList(paymentAmount);
        return Result.success(adminHomePageVo);
    }


}
